/**************************************************************************************
 *  Copyright (c)  2010  Leszek Karcz.
 *  Permission is granted to copy, distribute and/or modify this document
 *  under the terms of the GNU Free Documentation License, Version 1.3
 *  or any later version published by the Free Software Foundation;
 *  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
 *  A copy of the license is included in the section entitled "GNU
 *  Free Documentation License". 
 **************************************************************************************/
package data;
import data.tileables.*;

/**************************************************************************************
 * Author(s): Leszek Karcz
 * This class contains data for an individual "cell" on the map: terrain/items/units/etc.
 **************************************************************************************/
public class Tile
{
	private int x,y;
	private int terrain;
	private LinkedList<Controllable> controllables = new LinkedList<Controllable>();
	private LinkedList<Doodad> doodads = new LinkedList<Doodad>();

	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Tile constructor
	 **************************************************************************************/
	public Tile(int x, int y, int terrain)
	{
		this.x=x;
		this.y=y;
		this.terrain=terrain;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns whether the tile is passable or not
	 **************************************************************************************/
	public boolean isPassable(int playerID)
	{
		if(((this.terrain % 2)==0) && (!enemyPresent(playerID)))
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns the terrain type
	 **************************************************************************************/
	public int getTerrain()
	{
		return this.terrain;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns:
	 * -the terrain type
	 **************************************************************************************/
	public String getDecalImage()
	{
		String decal="";
		
		doodads.setCurrent(0);
		for(int i=0; i<doodads.getSize(); i++)
		{
			if(doodads.peekCurrent() instanceof Decal)
			{
				decal=doodads.peekCurrent().getImage();
				break;
			}
			doodads.next();
		}
		return decal;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns 0/1 int whether the tile has units or buildings belonging to a different player
	 **************************************************************************************/
	public boolean enemyPresent(int playerID)
	{
		boolean enemy=false;
		
		
		if(this.controllables.getSize()>0)
		{
			this.controllables.setCurrent(0);
			for(int i=0;i<this.controllables.getSize();i++)
			{
				if(this.controllables.peekCurrent().getPlayerID()!=playerID)
				{
					enemy=true;
					break;
				}
				else
				{
				this.controllables.next();
				}
			}
		}
		return enemy;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns structure
	 **************************************************************************************/
	public Structure getStructure()
	{
		Structure structure=null;
		
		if(controllables.getSize()>0)
		{
			controllables.setCurrent(controllables.getSize()-1);
			for(int i=0; i<controllables.getSize(); i++)
			{
				
				if(controllables.peekCurrent() instanceof Structure)
				{
					structure=(Structure)controllables.peekCurrent();
					break;
				}
				controllables.prev();
			}
		}
		return structure;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns whether there's a structure on this tile
	 **************************************************************************************/
	public boolean hasStructure()
	{
		return (getStructure()!=null);
	}	
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns top controllable with a certain displayLevel
	 **************************************************************************************/
	public Controllable getTopControllable(int displayLevel)
	{
		Controllable controllable=null;
		
		controllables.setCurrent(0);
		for(int i=0; i<controllables.getSize(); i++)
		{
			if(controllables.peekCurrent().getDisplayLevel()==displayLevel)
			{
				controllable=controllables.peekCurrent();
				break;
			}
			controllables.prev();
		}
		return controllable;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns list of all units on this tile
	 **************************************************************************************/
	public LinkedList<Unit> getUnits()
	{
		LinkedList<Unit> units=new LinkedList<Unit>();
		
		controllables.setCurrent(0);
		for(int i=0; i<controllables.getSize(); i++)
		{
			if(controllables.peekCurrent() instanceof Unit)
			{
				units.addBack((Unit)controllables.peekCurrent());
			}
			controllables.next();
		}
		return units;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns the top item on this tile
	 **************************************************************************************/
	public Item getTopItem()
	{
		Item item=null;
		
		doodads.setCurrent(doodads.getSize()-1);
		for(int i=0; i<doodads.getSize(); i++)
		{
			if(doodads.peekCurrent() instanceof Item)
			{
				item=(Item)doodads.peekCurrent();
				break;
			}
			doodads.prev();
		}
		return item;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns resources object
	 **************************************************************************************/
	public Resources getResources()
	{
		Resources resources=null;
		//iterate through doodads to get the resources
		if(this.doodads.getSize()>0)
		{
			this.doodads.setCurrent(0);
			for(int i=0;i<this.doodads.getSize();i++)
			{
				if(doodads.peekCurrent() instanceof Resources)
				{
					resources=(Resources)doodads.peekCurrent();
					break;
				}
				else
				{
				this.doodads.next();
				}
			}
		}
		return resources;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * adds a controllable to the list
	 **************************************************************************************/
	public boolean putControllable(Controllable controllable)
	{
		if(this.isPassable(controllable.getPlayerID()))
		{
			this.controllables.addBack(controllable);
			//get all items on the tile and apply to the controllable
			LinkedList<Item> items;
			items=this.getItems();
			if(items.getSize()>0)
			{
				items.setCurrent(0);
				for(int i=0;i<items.getSize();i++)
				{
					items.peekCurrent().execute(controllable);
					this.removeDoodad(items.peekCurrent());
					items.next();
				}
			}
			
			//get all area effects on the tile and apply to the controllable
			LinkedList<AreaEffect> areaEffect;
			areaEffect=this.getAreaEffects();
			if(areaEffect.getSize()>0)
			{
				areaEffect.setCurrent(0);
				for(int i=0;i<areaEffect.getSize();i++)
				{
					areaEffect.peekCurrent().execute(controllable);
					areaEffect.next();
				}
			}			
			return true;
		}
		else
		{
			return false;
		}
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * removes certain controllable from the list
	 **************************************************************************************/
	public void removeControllable(Controllable controllable)
	{
		if(this.controllables.getSize()>0)
		{
			this.controllables.setCurrent(0);
			for(int i=0;i<this.controllables.getSize();i++)
			{
				if(this.controllables.peekCurrent().equals(controllable))
				{
					this.controllables.removeCurrent();
					break;
				}
				else
				{
				this.controllables.next();
				}
			}
		}
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * adds a doodad to the list
	 **************************************************************************************/
	public void putDoodad(Doodad doodad)
	{
		this.doodads.addBack(doodad);
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * removes certain doodad from the list
	 **************************************************************************************/
	public void removeDoodad(Doodad doodad)
	{
		if(this.doodads.getSize()>0)
		{
			this.doodads.setCurrent(0);
			for(int i=0;i<this.doodads.getSize();i++)
			{
				if(this.doodads.peekCurrent().equals(doodad))
				{
					this.doodads.removeCurrent();
					break;
				}
				else
				{
				this.doodads.next();
				}
			}
		}
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns list of all items on this tile
	 **************************************************************************************/
	public LinkedList<Item> getItems()
	{
		LinkedList<Item> items=new LinkedList<Item>();
		
		doodads.setCurrent(0);
		for(int i=0; i<doodads.getSize(); i++)
		{
			if(doodads.peekCurrent() instanceof Item)
			{
				items.addBack((Item)doodads.peekCurrent());
			}
			doodads.next();
		}
		return items;
	}
	
	/**************************************************************************************
	 * Author(s): Leszek Karcz
	 * Returns list of all area effects on this tile
	 **************************************************************************************/
	public LinkedList<AreaEffect> getAreaEffects()
	{
		LinkedList<AreaEffect> areaEffects=new LinkedList<AreaEffect>();
		
		doodads.setCurrent(0);
		for(int i=0; i<doodads.getSize(); i++)
		{
			if(doodads.peekCurrent() instanceof AreaEffect)
			{
				areaEffects.addBack((AreaEffect)doodads.peekCurrent());
			}
			doodads.next();
		}
		return areaEffects;
	}
}
